//
// Created by Ctzzz on 2024/4/26.
//

#include "GLUtils.h"
#include "LogUtil.h"
#include <stdlib.h>


GLuint GLUtils::LoadShader(GLenum shaderType, const char *pSource) {
    GLuint shader = 0;
    FUN_BEGIN_TIME("GLUtils::LoadShader")
        // 创建着色器
        shader = glCreateShader(shaderType);
        if (shader) {
            // 设置着色器源码
            glShaderSource(shader, 1, &pSource, NULL);
            // 编译着色器
            glCompileShader(shader);
            GLint compiled = 0;
            // 获取编译状态
            glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
            if (!compiled) {
                GLint infoLen = 0;
                // 获取错误信息长度
                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
                if (infoLen) {
                    char *buf = (char *) malloc((size_t) infoLen);
                    if (buf) {
                        // 获取错误信息
                        glGetShaderInfoLog(shader, infoLen, NULL, buf);
                        LOGCATE("GLUtils::LoadShader Could not compile shader %d:\n%s\n",
                                shaderType, buf);
                        free(buf);
                    }
                    glDeleteShader(shader);
                    shader = 0;
                }
            }
        }
    FUN_END_TIME("GLUtils::LoadShader")
    return shader;
}


GLuint GLUtils::CreateProgram(const char *pVertexShaderSource, const char *pFragShaderSource,
                              GLuint &vertexShaderHandle, GLuint &fragShaderHandle) {
    GLuint program = 0;
    FUN_BEGIN_TIME("GLUtils::CreateProgram")
        // 创建顶点着色器
        vertexShaderHandle = LoadShader(GL_VERTEX_SHADER, pVertexShaderSource);
        if (!vertexShaderHandle) return program;
        // 创建片元着色器
        fragShaderHandle = LoadShader(GL_FRAGMENT_SHADER, pFragShaderSource);
        if (!fragShaderHandle) return program;

        // 创建程序对象
        program = glCreateProgram();
        if (program) {
            // 将顶点着色器附加到程序对象
            glAttachShader(program, vertexShaderHandle);
            CheckGLError("glAttachShader");
            // 将片元着色器附加到程序对象
            glAttachShader(program, fragShaderHandle);
            CheckGLError("glAttachShader");
            // 链接程序对象
            glLinkProgram(program);
            GLint linkStatus = GL_FALSE;
            // 获取链接状态
            glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

            /** 着色器添加到程序对象后，解绑操作，对吗？？？存疑*/
            glDetachShader(program, vertexShaderHandle);
            glDeleteShader(vertexShaderHandle);
            vertexShaderHandle = 0;
            glDetachShader(program, fragShaderHandle);
            glDeleteShader(fragShaderHandle);
            fragShaderHandle = 0;

            if (linkStatus != GL_TRUE) {
                GLint bufLength = 0;
                // 获取错误信息长度
                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
                if (bufLength) {
                    char *buf = (char *) malloc((size_t) bufLength);
                    if (buf) {
                        // 获取错误信息
                        glGetProgramInfoLog(program, bufLength, NULL, buf);
                        LOGCATE("GLUtils::CreateProgram Could not link program:\n%s\n", buf);
                        free(buf);
                    }
                }
                // 删除程序对象
                glDeleteProgram(program);
                program = 0;
            }
        }
    FUN_END_TIME("GLUtils::CreateProgram")
    LOGCATE("GLUtils::CreateProgram program = %d", program);
    return program;
}


void GLUtils::DeleteProgram(GLuint &program) {
    LOGCATE("GLUtils::DeleteProgram");
    if (program) {
        // 使用程序对象作为当前渲染状态的一部分,当program为0时，表示引用无效的对象
        glUseProgram(0);
        // 删除程序对象
        glDeleteProgram(program);
        program = 0;
    }
}

void GLUtils::CheckGLError(const char *pGLOperation) {
    for (GLint error = glGetError(); error; error = glGetError()) {
        LOGCATE("GLUtils::CheckGLError GL Operation %s() glError (0x%x)\n", pGLOperation,
                error);
    }
}
